#include "adc.h"

/**
  *************************************************************************************************
  * @file     adc.c
  * @author   唐友源
  * @version  V1.0.0
  * @date     2021.7.23
  * @brief    adc模式初始化
  * @remarks 
  **************************************************************************************************
  * @attention   1、STM32F407共3个ADC，每个ADC有15个通道，可分别使用，最快转换时间为0.71us
  *              2、使用不同ADC和引脚直接修改宏定义即可
  *              3、本实验配置ADC转换中断，一次最多配置3个通道口同时采集，3个通道必须分属3个不同的ADC，因为只有ADC的转换中断，没有通道的转换中断
  *              4、需要同时开启3个级以上的通道采集时，可采用正点原子的ADC例程，采用分时复用。
  *              5、ADC开启多通道可采用DMA传输，这里不多做描述，可自行探索
  *              6、本实验例程尾部附上正点原子例程修改后的分时复用五路ADC通道采集
  **************************************************************************************************
  */

// ADC GPIO 宏定义
#define RHEOSTAT_ADC_GPIO_PORT    GPIOA
#define RHEOSTAT_ADC_GPIO_PIN     GPIO_Pin_6
#define RHEOSTAT_ADC_GPIO_CLK     RCC_AHB1Periph_GPIOA
 
// ADC 序号宏定义
#define RHEOSTAT_ADC              ADC2
#define RHEOSTAT_ADC_CLK          RCC_APB2Periph_ADC2
#define RHEOSTAT_ADC_CHANNEL      ADC_Channel_6
#define RHEOSTAT_NOFCHANEL        1
 
// ADC 中断宏定义
#define Rheostat_ADC_IRQ            ADC_IRQn
#define Rheostat_ADC_INT_FUNCTION   ADC_IRQHandler
										   
//ADC中断配置
static void ADC_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	
	NVIC_InitStructure.NVIC_IRQChannel = Rheostat_ADC_IRQ;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 
	NVIC_Init(&NVIC_InitStructure);
}

//ADC通道引脚配置
static void ADC_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;  
    RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK, ENABLE);  // 使能 GPIO 时钟
 
    // 配置 IO
    GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉
    GPIO_Init(RHEOSTAT_ADC_GPIO_PORT, &GPIO_InitStructure);
}

//ADC模式配置
static void ADC_Mode_Config(void)
{
    ADC_InitTypeDef ADC_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    
    RCC_APB2PeriphClockCmd(RHEOSTAT_ADC_CLK , ENABLE);// 开启ADC时钟
 
    // -------------------ADC Common 结构体 参数 初始化------------------------    
    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;// 独立ADC模式    
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;// 时钟为fpclk x分频    
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;// 禁止DMA直接访问模式    
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;// 采样时间间隔
    ADC_CommonInit(&ADC_CommonInitStructure);
 
    // -------------------ADC Init 结构体 参数 初始化--------------------------
    ADC_StructInit(&ADC_InitStructure);    
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;// ADC 分辨率    
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;// 禁止扫描模式，多通道采集才需要    
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;// 连续转换    
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止外部边沿触发    
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;//外部触发通道，本例子使用软件触发，此值随便赋值即可
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐    
    ADC_InitStructure.ADC_NbrOfConversion = RHEOSTAT_NOFCHANEL;//转换通道 1个
    ADC_Init(RHEOSTAT_ADC, &ADC_InitStructure);
	
    //---------------------------------------------------------------------------    
    ADC_RegularChannelConfig(RHEOSTAT_ADC, RHEOSTAT_ADC_CHANNEL, 1, ADC_SampleTime_56Cycles);// 配置 ADC 通道转换顺序为1，第一个转换，采样时间为3个时钟周期
    ADC_ITConfig(RHEOSTAT_ADC, ADC_IT_EOC, ENABLE);// ADC 转换结束产生中断，在中断服务程序中读取转换值    
    ADC_Cmd(RHEOSTAT_ADC, ENABLE);// 使能ADC    
    ADC_SoftwareStartConv(RHEOSTAT_ADC);//开始adc转换，软件触发
}

//ADC初始化
void ADC_Config_Init(void){
	ADC_GPIO_Config();
	ADC_Mode_Config();
	ADC_NVIC_Config();
}

__IO uint16_t ADC_ConvertedValue;

void ADC_IRQHandler(void)
{
	if(ADC_GetITStatus(RHEOSTAT_ADC,ADC_IT_EOC)==SET)
	{
  // 读取ADC的转换值
		ADC_ConvertedValue = ADC_GetConversionValue(RHEOSTAT_ADC);
	}
	ADC_ClearITPendingBit(RHEOSTAT_ADC,ADC_IT_EOC);
}
	 
//////////////////////////////////////////////////////////////////////////////////	 
//本程序只供学习使用，未经作者许可，不得用于其它任何用途
//ALIENTEK STM32F407开发板
//ADC 驱动代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2014/5/6
//版本：V1.0
//版权所有，盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved									  
////////////////////////////////////////////////////////////////////////////////// 	


//初始化ADC															   
void  Adc_Init(void)
{    
   GPIO_InitTypeDef  GPIO_InitStructure;
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	ADC_InitTypeDef       ADC_InitStructure;
	
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1时钟

  //先初始化ADC1通道5 IO口
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;//通道1 - 通道5
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不带上下拉
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化  
 
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);	  //ADC1复位
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);	//复位结束	 
 
	
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间的延迟5个时钟
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //DMA失能
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz 
  ADC_CommonInit(&ADC_CommonInitStructure);//初始化
	
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式	
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止触发检测，使用软件触发
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐	
  ADC_InitStructure.ADC_NbrOfConversion = 1;//1个转换在规则序列中 也就是只转换规则序列1 
  ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化
	
 
  ADC_Cmd(ADC1, ENABLE);//开启AD转换器	

}				  
//获得ADC值
//ch: @ref ADC_channels 
//通道值 0~16取值范围为：ADC_Channel_0~ADC_Channel_16
//返回值:转换结果
u16 Get_Adc(u8 ch)   
{
	  	//设置指定ADC的规则组通道，一个序列，采样时间
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_480Cycles );	//ADC1,ADC通道,480个周期,提高采样时间可以提高精确度			    
  
	ADC_SoftwareStartConv(ADC1);		//使能指定的ADC1的软件转换启动功能	
	 
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

	return ADC_GetConversionValue(ADC1);	//返回最近一次ADC1规则组的转换结果
}
//获取通道ch的转换值，取times次,然后平均 
//ch:通道编号
//times:获取次数
//返回值:通道ch的times次转换结果平均值
u16 Get_Adc_Average(u8 ch,u8 times)
{
	u32 temp_val=0;
	u8 t;
	for(t=0;t<times;t++)
	{
		temp_val+=Get_Adc(ch);
		delay_ms(5);
	}
	return temp_val/times;
} 
	 









